/**
 * All Rights Reserved , Copyright (C) 2020 , 青岛鼎信通讯股份有限公司
 * <p>
 * PmInvoiceApplyService
 * 项目合同开票申请
 * <p>
 * 修改纪录
 * 2020-05-19 版本：1.0 wushenghong 创建。
 *
 * @version 版本：1.0
 * @author 作者：wushenghong
 * 创建日期：2020-05-19
 */
package com.topscomm.pm.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.topscomm.basic.BasicEntity;
import com.topscomm.basic.exception.BusinessException;
import com.topscomm.basic.exception.ServiceException;
import com.topscomm.basic.util.PrimaryKeyUtil;
import com.topscomm.cbo.pojo.CboApprovalNodeEntity;
import com.topscomm.cbo.pojo.CboApprovalNodeInsEntity;
import com.topscomm.cbo.pojo.CboOrgEntity;
import com.topscomm.cbo.pojo.CboUserEntity;
import com.topscomm.cbo.service.ICboApprovalNodeInsService;
import com.topscomm.cbo.service.impl.CboAttachmentService;
import com.topscomm.pm.PmSystemConst;
import com.topscomm.pm.pojo.PmInvoiceApplyEntity;
import com.topscomm.pm.pojo.PmInvoiceRecordEntity;
import com.topscomm.pm.pojo.PmProjectEntity;
import com.topscomm.pm.service.IPmInvoiceApplyService;
import com.topscomm.pm.service.IPmInvoiceRecordService;
import com.topscomm.pm.service.IPmProjectService;
import com.topscomm.pm.service.impl.auto.PmInvoiceApplyServiceAuto;
import com.topscomm.pub.util.ConvertUtil;
import com.topscomm.pub.util.SpringUtil;
import com.topscomm.pub.util.StringBufferProxy;
import com.topscomm.pub.util.StringUtil;
import com.topscomm.tap.TapEntity;
import com.topscomm.tap.common.DatacodeCache;
import com.topscomm.tap.common.ParameterCache;
import com.topscomm.tap.common.SessionUserBean;
import org.apache.commons.collections4.map.HashedMap;
import org.springframework.context.annotation.Scope;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service(value = "pmInvoiceApplyService")
@Scope(value = "singleton")
public class PmInvoiceApplyService extends PmInvoiceApplyServiceAuto implements IPmInvoiceApplyService {
    @Resource(name = "pmProjectService")
    private IPmProjectService pmProjectService;
    @Resource(name = "cboApprovalNodeInsService")
    private ICboApprovalNodeInsService cboApprovalNodeInsService;
    @Resource(name = "datacodeCache")
    private DatacodeCache datacodeCache;
    @Resource(name = "pmInvoiceRecordService")
    private IPmInvoiceRecordService pmInvoiceRecordService;

    /**
     * @param entity
     * @throws
     * @author: wushenghong
     * @date: 2020-05-19
     * @description:单号生成
     * @modify:
     */
    @Override
    protected void beforeInsert(BasicEntity entity) {
        super.beforeInsert(entity);
        if (entity.getId() <= 0) {// 赋值Id和单号
            long[] arrayId = PrimaryKeyUtil.GeneIDs(entity.getTableName(), 1);
            entity.setId(arrayId[0]);
            String docNo = String.valueOf(arrayId[0]);
            docNo = docNo.substring(0, 6) + docNo.substring(9);
            entity.setValue(PmInvoiceApplyEntity.FieldDocno, docNo);
            // 判断是否是作废，如果是则复制相关信息
            this.initCancelInfo(entity);
        }
    }

    /**
     * @return
     * @author: shenyouyi
     * @date: 2020-09-25
     * @param: map
     * @description: 重写更新之前的操作
     * @modify:
     */
    @Override
    protected void updateBefore(Map<String, Object> map) throws ServiceException {
        super.updateBefore(map);
        Object oldidObj = map.getOrDefault("oldid", null);
        String oldidStr = ConvertUtil.convertToString(oldidObj);
        if (!StringUtil.isEmpty(oldidStr) && (long) map.get("oldid") > 0 && PmSystemConst.DocTypeEnum.cancel.equals(map.get("category")) && map.get("customerid") == null) {// 作废的时候复制之前的值
            PmInvoiceApplyEntity pmInvoiceApplyEntity = new PmInvoiceApplyEntity();
            BasicEntity basicEntity = pmInvoiceApplyEntity.convertFromMap(map);
            pmInvoiceApplyEntity = this.initCancelInfo(basicEntity);
            Map<String, Object> originMap = pmInvoiceApplyEntity.convertToMap();
            this.mapCopy(originMap, map);
        }
    }

    /**
     * @return
     * @author: shenyouyi
     * @date: 2020-09-26
     * @param: entity
     * @param: sessionUserBean
     * @description: 重写提交之前的方法
     * @modify:
     */
    @Transactional
    @Override
    protected void beforeSubmit(TapEntity entity, SessionUserBean sessionUserBean) {
        super.beforeSubmit(entity, sessionUserBean);
        PmInvoiceApplyEntity pmInvoiceApplyEntity = (PmInvoiceApplyEntity) entity;
        String category = pmInvoiceApplyEntity.getCategory();
        if (!category.equals(PmSystemConst.DocTypeEnum.New)) {// 如果是作废护着作废重开，先校验原发票号是否有效
            String invoicecodes = pmInvoiceApplyEntity.getOldinvoicecode();
            String[] billNoArray = invoicecodes.split(",");
            StringBufferProxy invoicecodePara = new StringBufferProxy();
            for (String oldinvoicecodeStr : billNoArray) {
                invoicecodePara.appendSingle("'{0}',", oldinvoicecodeStr);
            }
            invoicecodePara = invoicecodePara.length() > 0 ? invoicecodePara.substring(0, invoicecodePara.length() - 1) : invoicecodePara;
            StringBufferProxy sql = new StringBufferProxy();
            sql.appendSingle("invoiceapplyid = {0} and invoiceno in ({1})", pmInvoiceApplyEntity.getOldid(), invoicecodePara.toString());
            List<PmInvoiceRecordEntity> invoiceRecordList = pmInvoiceRecordService.queryByWhere(sql.toString());
            StringBufferProxy invoiceNos = new StringBufferProxy();
            for (PmInvoiceRecordEntity invoiceRecord : invoiceRecordList) {
                if (!invoiceRecord.getIscancel().equals(PmSystemConst.InvoiceCancelStatusEnum.Enabled)) {
                    invoiceNos.appendSingle(invoiceRecord.getInvoiceno() + ",");
                }
            }
            if (invoiceNos.length() > 0) {
                invoiceNos = invoiceNos.substring(0, invoiceNos.length() - 1);
                throw new BusinessException("发票号【" + invoiceNos + "】已作废或者处于作废申请中，不允许操作。");
            }
            // 将这些发票号改为作废中状态
            for (PmInvoiceRecordEntity invoiceRecord : invoiceRecordList) {
                invoiceRecord.setIscancel(PmSystemConst.InvoiceCancelStatusEnum.Canceling);
                pmInvoiceRecordService.updateEntity(invoiceRecord);
            }
        }
    }

    /**
     * @return
     * @author: shenyouyi
     * @date: 2020-09-25
     * @param: originMap
     * @param: destMap
     * @description: 拷贝两个Map
     * @modify:
     */
    private void mapCopy(Map<String, Object> originMap, Map<String, Object> destMap) {
        if (destMap == null) destMap = new HashMap<>();
        if (originMap == null) return;

        Iterator it = originMap.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String key = (String) entry.getKey();
            destMap.put(key, originMap.get(key) != null ? originMap.get(key) : "");
        }
    }

    /**
     * @return
     * @author: shenyouyi
     * @date: 2020-09-25
     * @param: entity
     * @description: 初始化作废信息
     * @modify:
     */
    private PmInvoiceApplyEntity initCancelInfo(BasicEntity entity) {
        PmInvoiceApplyEntity pmInvoiceApplyEntity = (PmInvoiceApplyEntity) entity;
        String category = pmInvoiceApplyEntity.getCategory();
        if (PmSystemConst.DocTypeEnum.cancel.equals(category)) {// 如果是作废
            // 开票金额设置为0
            pmInvoiceApplyEntity.setInvoicemoney(BigDecimal.ZERO);
            // 将原申请单相关信息复制过来
            long oldid = pmInvoiceApplyEntity.getOldid();
            PmInvoiceApplyEntity oldInvoiceApply = this.queryById(String.valueOf(oldid));
            pmInvoiceApplyEntity.setInvoicename(oldInvoiceApply.getInvoicename());
            pmInvoiceApplyEntity.setCustomerid(oldInvoiceApply.getCustomerid());
            pmInvoiceApplyEntity.setCustomername(oldInvoiceApply.getCustomername());
            pmInvoiceApplyEntity.setInvoicetype(oldInvoiceApply.getInvoicetype());
            pmInvoiceApplyEntity.setInvoicedate(oldInvoiceApply.getInvoicedate());
            pmInvoiceApplyEntity.setDemand(oldInvoiceApply.getDemand());
            pmInvoiceApplyEntity.setExplain(oldInvoiceApply.getExplain());
            pmInvoiceApplyEntity.setInvoiceorgname(oldInvoiceApply.getInvoiceorgname());
            pmInvoiceApplyEntity.setInvoiceorgcode(oldInvoiceApply.getInvoiceorgcode());
            pmInvoiceApplyEntity.setInvoicedeptname(oldInvoiceApply.getInvoicedeptname());
            pmInvoiceApplyEntity.setInvoicedeptcode(oldInvoiceApply.getInvoicedeptcode());
            pmInvoiceApplyEntity.setErpcode(oldInvoiceApply.getErpcode());
            pmInvoiceApplyEntity.setCompanyname(oldInvoiceApply.getCompanyname());
            pmInvoiceApplyEntity.setBankname(oldInvoiceApply.getBankname());
            pmInvoiceApplyEntity.setBankaccount(oldInvoiceApply.getBankaccount());
            pmInvoiceApplyEntity.setTaxno(oldInvoiceApply.getTaxno());
            pmInvoiceApplyEntity.setCompanyaddress(oldInvoiceApply.getCompanyaddress());
            pmInvoiceApplyEntity.setReceiver(oldInvoiceApply.getReceiver());
            pmInvoiceApplyEntity.setReceivertel(oldInvoiceApply.getReceivertel());
            pmInvoiceApplyEntity.setCompanytel(oldInvoiceApply.getCompanytel());
            pmInvoiceApplyEntity.setMailaddress(oldInvoiceApply.getMailaddress());
            pmInvoiceApplyEntity.setMailaddress2(oldInvoiceApply.getMailaddress2());
            // pmInvoiceApplyEntity.setInvoiceno(oldInvoiceApply.getInvoiceno());
            // 作废的时候，发票号填写选择的作废的发票号
            pmInvoiceApplyEntity.setInvoiceno(pmInvoiceApplyEntity.getOldinvoicecode());
            pmInvoiceApplyEntity.setCouriernumber(oldInvoiceApply.getCouriernumber());
            pmInvoiceApplyEntity.setCourier(oldInvoiceApply.getCourier());
            pmInvoiceApplyEntity.setMaildate(oldInvoiceApply.getMaildate());
            pmInvoiceApplyEntity.setIscancel("0");
            pmInvoiceApplyEntity.setOldcustomername(oldInvoiceApply.getCustomername());
            pmInvoiceApplyEntity.setOldinvoicedate(oldInvoiceApply.getInvoicedate());
            // 设置原开票金额 = 选择作废的发票金额总和
            String oldinvoicebillmoney = pmInvoiceApplyEntity.getOldinvoicebillmoney();
            String[] oldbillmoneyArray = oldinvoicebillmoney.split(",");
            BigDecimal oldInvoiceMoney = BigDecimal.ZERO;
            for (String oldbillmoney : oldbillmoneyArray) {
                oldInvoiceMoney = oldInvoiceMoney.add(new BigDecimal(oldbillmoney));
            }
            pmInvoiceApplyEntity.setOldinvoicemoney(oldInvoiceMoney);
            pmInvoiceApplyEntity.setOldnumber(oldInvoiceApply.getCouriernumber());
        }
        return pmInvoiceApplyEntity;
    }

    /**
     * @param
     * @throws
     * @author: wushenghong
     * @date: 2020-06-13
     * @description:开票金额计算
     * @modify:
     */
    public void updateBillMoneyOfProjectBase(String sourceId, boolean approvalSuccess) {
        PmInvoiceApplyEntity pmInvoiceApplyEntity = this.queryById(sourceId);
        if (!approvalSuccess) {// 取消审批回退原单据状态
            if (!ObjectUtil.isEmpty(pmInvoiceApplyEntity)) {
                if (!(PmSystemConst.DocTypeEnum.New.equals(pmInvoiceApplyEntity.getCategory()))) {
                    Long oldId = pmInvoiceApplyEntity.getOldid();
                    Map<String, Object> updateParam = new HashedMap<>();
                    updateParam.put("id", oldId);
                    updateParam.put("iscancel", '0');
                    this.update(updateParam);
                }
            }
        }
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle("select sum(NVL(invoicemoney,0)) as totaladdmoney, sum(NVL(oldinvoicemoney,0)) as totalsubtractmoney from PmInvoiceApply where projectid = {0} and state = 9 and id <> {1}", pmInvoiceApplyEntity.getProjectid(), sourceId);
        BigDecimal totalMoney = BigDecimal.ZERO;
        if (approvalSuccess) {
            // 新增、作废、重开
            if (PmSystemConst.DocTypeEnum.New.equals(pmInvoiceApplyEntity.getCategory())) {
                totalMoney = pmInvoiceApplyEntity.getInvoicemoney();
            } else if (PmSystemConst.DocTypeEnum.cancel.equals(pmInvoiceApplyEntity.getCategory())) {
                totalMoney = pmInvoiceApplyEntity.getOldinvoicemoney().negate();
            } else if (PmSystemConst.DocTypeEnum.cancelReOpen.equals(pmInvoiceApplyEntity.getCategory())) {
                totalMoney = pmInvoiceApplyEntity.getInvoicemoney().subtract(pmInvoiceApplyEntity.getOldinvoicemoney());
            }
        }
        List<Map<String, Object>> moneyList = this.selectExecute(sql.toString());
        if (moneyList.size() > 0) {
            BigDecimal partAddMoney = (BigDecimal) moneyList.get(0).get("totaladdmoney");
            BigDecimal partSubtractMoney = (BigDecimal) moneyList.get(0).get("totalsubtractmoney");
            totalMoney = totalMoney.add(partAddMoney).subtract(partSubtractMoney);
        }
        // 更新项目表中的金额
        sql.clear();
        sql.appendSingle("update pmproject set billmoney = {0} where id = {1}", totalMoney, pmInvoiceApplyEntity.getProjectid());
        this.updateExecute(sql.toString());
    }

    /**
     * @return
     * @author: shenyouyi
     * @date: 2020-09-26
     * @param: paraMap
     * @description: 发票系统回调
     * @modify:
     */
    @Transactional
    public void invoiceCallback(Map<String, Object> paraMap) throws Exception {
        if (paraMap.size() == 0) {
            throw new BusinessException("推送数据有误！");
        }
        String eventType = "";
        if (paraMap.containsKey("eventType")) {
            eventType = paraMap.get("eventType").toString();
        } else {
            throw new BusinessException("推送数据无eventType字段！");
        }
        Map<String, Object> dataObject = null;
        if (paraMap.containsKey("data")) {
            dataObject = (Map<String, Object>) paraMap.get("data");
        } else {
            throw new BusinessException("推送数据无data数据！");
        }
        if (dataObject.size() == 0) {
            throw new BusinessException("推送数据data中无具体数据！");
        }
        // 获取单据信息
        String sourceDocNo = "";
        if (dataObject.containsKey("sourceid")) {
            sourceDocNo = dataObject.get("sourceid").toString();
        } else {
            throw new BusinessException("推送数据data中sourceid数据！");
        }
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle(" docno = '{0}'", sourceDocNo);
        PmInvoiceApplyEntity pmInvoiceApplyEntity = this.queryObjectByWhere(sql.toString());
        String sourceId = ConvertUtil.convertToString(pmInvoiceApplyEntity.getId());
        String category = pmInvoiceApplyEntity.getCategory();
        String sourceType = pmInvoiceApplyEntity.getTableName();
        //获取流程id
        String auditFlowId = ConvertUtil.convertToString(pmInvoiceApplyEntity.getFlowid());
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        if (eventType.equals(PmSystemConst.SysApiNoticeTypeEnum.CheckFailed)) {
            // 审核不通过的处理逻辑
            // 开票平台对应的审批节点
            Long autoApprovalNodeId = ConvertUtil.convertToLong(datacodeCache
                    .getValueDynamic("PmInvoiceAutoCheckNode", auditFlowId, "code", "name"));
            if (autoApprovalNodeId == 0) {
                throw new BusinessException("缺少开票申请单自动化自动审批节点的编码配置！");
            }
            sql.clear();
            sql.appendLineSingle(" SourceType='{0}' and SourceId={1} and NodeId={2} and state=1 ", sourceType,
                    sourceId, autoApprovalNodeId);
            List<CboApprovalNodeInsEntity> cboApprovalNodeInsEntityList = cboApprovalNodeInsService.queryByWhere(sql.toString());
            if (cboApprovalNodeInsEntityList == null || cboApprovalNodeInsEntityList.size() == 0) {
                throw new BusinessException("没有找到对应的审批节点实例！");
            }
            String approvalNodeInstanceId = ConvertUtil.convertToString(cboApprovalNodeInsEntityList.get(0).getId());
            createUserBean();
            this.executeApprove(approvalNodeInstanceId, null, null,
                    PmSystemConst.ApprovalTypeEnum.APPROVAL_FAIL, this.getSessionUserBean());
            // 如果是作废重开审核驳回，把原发票号改为正常状态
            if(!category.equals(PmSystemConst.DocTypeEnum.New)){
                pmInvoiceRecordService.setInvoiceState(pmInvoiceApplyEntity.getOldid(), pmInvoiceApplyEntity.getOldinvoicecode(), PmSystemConst.InvoiceCancelStatusEnum.Enabled);
            }
        } else if (eventType.equals(PmSystemConst.SysApiNoticeTypeEnum.CheckSuccess)) {
            // 审核通过的处理逻辑
            // 开票平台审批节点
            Long autoApprovalNodeId = ConvertUtil.convertToLong(this.datacodeCache
                    .getValueDynamic("PmInvoiceAutoCheckNode", auditFlowId, "code", "name"));
            if (autoApprovalNodeId == 0) {
                throw new BusinessException("缺少开票申请单自动化自动审批节点的编码配置！");
            }
            sql.clear();
            sql.appendLineSingle(" SourceType='{0}' and SourceId={1} and NodeId={2} and state=1 ", sourceType,
                    sourceId, autoApprovalNodeId);
            List<CboApprovalNodeInsEntity> cboApprovalNodeInsEntityList = cboApprovalNodeInsService.queryByWhere(sql.toString());
            if (cboApprovalNodeInsEntityList == null || cboApprovalNodeInsEntityList.size() == 0) {
                throw new BusinessException("没有找到对应的审批节点实例！");
            }
            // 如果是作废重开审核通过，将原发票号作废
            if (!category.equals(PmSystemConst.DocTypeEnum.New)) {
                pmInvoiceRecordService.setInvoiceState(pmInvoiceApplyEntity.getOldid(), pmInvoiceApplyEntity.getOldinvoicecode(), PmSystemConst.InvoiceCancelStatusEnum.Canceled);
            }
            String approvalNodeInstanceId = ConvertUtil.convertToString(cboApprovalNodeInsEntityList.get(0).getId());
            createUserBean();
            this.executeApprove(approvalNodeInstanceId, null, null,
                    PmSystemConst.ApprovalTypeEnum.APPROVAL_SUCCESS, this.getSessionUserBean());
        } else if (eventType.equals(PmSystemConst.SysApiNoticeTypeEnum.InvoiceApplyDrop)) {
            //销售开票平台失效---走取消审批
            PmInvoiceApplyEntity invoiceEntity = this.queryById(sourceId);
            PmProjectEntity pmProjectEntity = pmProjectService
                .queryById(ConvertUtil.convertToString(invoiceEntity.getProjectid()));
            // 如果该开票单据(新增的)已经审批结束，然后发票平台又将该单据失效了，则需要把工程项目上的 开票总金额-失效的开票金额
            if(category.equals(PmSystemConst.DocTypeEnum.New)&&invoiceEntity.getState()==9){
                BigDecimal money = pmProjectEntity.getBillmoney()
                    .subtract(invoiceEntity.getInvoicemoney());
                HashMap<String, Object> map = new HashMap<>();
                map.put("id",pmProjectEntity.getId());
                map.put("billmoney",money);
                pmProjectService.update(map);
            }
            createUserBean();
            this.executeDelApprove(sourceId, this.getSessionUserBean());
            if (!category.equals(PmSystemConst.DocTypeEnum.New)) {// 作废重开失效，将老发票修改为有效状态
                pmInvoiceRecordService.setInvoiceState(pmInvoiceApplyEntity.getOldid(), pmInvoiceApplyEntity.getOldinvoicecode(), PmSystemConst.InvoiceCancelStatusEnum.Enabled);
            }
        } else if (eventType.equals(PmSystemConst.SysApiNoticeTypeEnum.LogisticsInfoChange)) {
            // 物流信息更新的处理逻辑
            String billSendDate = ConvertUtil.convertToString(dataObject.get("senddate"));
            String expressDocNo = ConvertUtil.convertToString(dataObject.get("logisticsno"));
            String expressType = ConvertUtil.convertToString(dataObject.get("sendway"));
            pmInvoiceApplyEntity.setCouriernumber(expressDocNo);
            pmInvoiceApplyEntity.setCourier(expressType);
            pmInvoiceApplyEntity.setMaildate(simpleDateFormat.parse(billSendDate));
            this.updateEntity(pmInvoiceApplyEntity);
        } else if (eventType.equals(PmSystemConst.SysApiNoticeTypeEnum.InvoiceInfoChange)) {
            // 发票信息更新的处理逻辑
            String bilDateString = ConvertUtil.convertToString(dataObject.get("billdate"));
            String billNo = ConvertUtil.convertToString(dataObject.get("billno"));
            Date billDate = simpleDateFormat.parse(bilDateString);
            String billmoney = ConvertUtil.convertToString(dataObject.get("billmoney"));
            // 多个发票按照从小到大顺序排序
            List<String> billNoList = Arrays.asList(billNo.split(","));
            // 更新开票申请单的发票号、开票日期、发票金额
            pmInvoiceApplyEntity.setInvoiceno(billNoList.stream().sorted(Comparator.comparing(Long::parseLong)).collect(Collectors.joining(",")));
            pmInvoiceApplyEntity.setInvoicebillmoney(billmoney);
            pmInvoiceApplyEntity.setInvoicedate(billDate);
            this.updateEntity(pmInvoiceApplyEntity);
            // 写入发票记录表
            String[] billNoArray = billNo.split(",");
            String[] billMoneyArray = billmoney.split(",");
            List<BasicEntity> pmInvoiceRecordEntityList = new ArrayList<>();
            for (int i = 0; i < billNoArray.length; i++) {
                // 如果该发票信息之前保存过，则本次不插入
                sql.clear();
                sql.appendSingle(PmInvoiceRecordEntity.FieldInvoiceno + " = '{0}'", billNoArray[i]);
                int count = pmInvoiceRecordService.getCount(sql.toString());
                if(count>0){
                    continue;
                }
                PmInvoiceRecordEntity pmInvoiceRecordEntity = new PmInvoiceRecordEntity();
                pmInvoiceRecordEntity.setProjectid(pmInvoiceApplyEntity.getProjectid());
                pmInvoiceRecordEntity.setProjectcode(pmInvoiceApplyEntity.getProjectcode());
                pmInvoiceRecordEntity.setInvoiceapplyid(pmInvoiceApplyEntity.getId());
                pmInvoiceRecordEntity.setInvoiceapplydocno(pmInvoiceApplyEntity.getDocno());
                pmInvoiceRecordEntity.setInvoicedate(pmInvoiceApplyEntity.getInvoicedate());
                pmInvoiceRecordEntity.setInvoiceno(billNoArray[i]);
                pmInvoiceRecordEntity.setInvoicebillmoney(i < billMoneyArray.length ? billMoneyArray[i] : "0");
                pmInvoiceRecordEntity.setIscancel(PmSystemConst.InvoiceCancelStatusEnum.Enabled);
                pmInvoiceRecordEntityList.add(pmInvoiceRecordEntity);
            }
            pmInvoiceRecordService.insertBatch(pmInvoiceRecordEntityList);
            // 标准出货单、出货单审批、应收单审批
            PmProjectEntity pmProjectEntity = pmProjectService.queryById(ConvertUtil.convertToString(pmInvoiceApplyEntity.getProjectid()));
            if (pmProjectEntity.getCreateon().compareTo(com.topscomm.pub.util.DateUtil.stringToDate(PmSystemConst.InvoiceApplyOnlineDate)) >= 0) {
                JSONObject exceptionRes1 = this.pmAddErpShip(pmInvoiceApplyEntity);
                if (exceptionRes1.getBooleanValue("success")) {
                    JSONObject exceptionRes2 = this.pmAddErpShipApproval(pmInvoiceApplyEntity);
                    if (exceptionRes2.getBooleanValue("success")) {
                        JSONObject exceptionRes3 = this.pmAddErpArbill(pmInvoiceApplyEntity);
                        if (!exceptionRes3.getBooleanValue("success")) {
                            this.startApprovalInvoice(pmInvoiceApplyEntity, exceptionRes3);
                        }
                    } else {
                        this.startApprovalInvoice(pmInvoiceApplyEntity, exceptionRes2);
                    }
                } else {
                    this.startApprovalInvoice(pmInvoiceApplyEntity, exceptionRes1);
                }
            }
        }
    }

    /**
     * @return
     * @author: shenyouyi
     * @date: 2020-09-26
     * @description: 构建用户session
     * @modify:
     */
    public void createUserBean() {
        // 设置系统自动更新上下文信息
        CboOrgEntity org = new CboOrgEntity();
        CboUserEntity user = new CboUserEntity();
        SessionUserBean userBean = this.getSessionUserBean();
        if (userBean == null) {
            userBean = new SessionUserBean();
        }

        user.setName("SystemMeterBom");
        user.setId(98);
        user.setAdminlevel(1);
        userBean.setUser(user);

        org.setId(98);
        org.setName("SystemMeterBom");
        org.setCode("SystemMeterBom");
        userBean.setOrg(org);

        userBean.setWorkOrg(org);
    }

    // 远程调用方法header无添加内容
    public JSONObject remoteRequestMethod(JSONObject map, String paraUrl) {
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
        requestFactory.setConnectTimeout(2000);// 设置超时
        requestFactory.setReadTimeout(200000);//读取超时时间
        RestTemplate restTemplate = new RestTemplate(requestFactory);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
        HttpEntity<JSONObject> request = new HttpEntity<>(map, headers);
        ResponseEntity<JSONObject> response = restTemplate.postForEntity(paraUrl, request, JSONObject.class);
        return response.getBody();
    }

    // 远程调用方法
    public JSONObject remoteRequestMethod(JSONObject map, String paraValue, String paraUrl) {
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
        requestFactory.setConnectTimeout(2000);// 设置超时
        requestFactory.setReadTimeout(200000);//读取超时时间
        RestTemplate restTemplate = new RestTemplate(requestFactory);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
        headers.set("token", paraValue);
        HttpEntity<JSONObject> request = new HttpEntity<>(map, headers);
        ResponseEntity<JSONObject> response = restTemplate.postForEntity(paraUrl, request, JSONObject.class);
        return response.getBody();
    }
    /**
     * @Title: pmAddErpShip
     * @Description: 自动生成出货订单
     * @author houyuhang
     * @date  2023年1月17日
     */
    @Transactional(rollbackFor = Exception.class)
    public JSONObject pmAddErpShip(PmInvoiceApplyEntity pmInvoiceApplyEntity) throws Exception {
        String paraUrl = ParameterCache.getValue("ERPServiceUrl_CreateShip");
        String paraValue = ParameterCache.getValue("ERPServiceUrl_Token");
        String orgcode = pmInvoiceApplyEntity.getInvoiceorgcode();
        JSONObject map = new JSONObject();
        map.put("system", "pm");
        map.put("ident", pmInvoiceApplyEntity.getTableName()+"_"+pmInvoiceApplyEntity.getId());
        map.put("orgCode", orgcode);
        if("D1".equals(orgcode)) {
            map.put("documentType", "SM1");
        } else if ("D22".equals(orgcode)) {
            map.put("documentType", "SM2");
        } else {
            map.put("documentType", "SM1");
        }
        map.put("businessDate", new Date());
        // 出货行信息
        ArrayList list = new ArrayList();
        JSONObject line = new JSONObject();
        line.put("orgCode", orgcode);
        line.put("docNo", pmInvoiceApplyEntity.getErpdocno());
        line.put("docLineNo", 10);
        line.put("qty", 1);
        list.add(line);
        map.put("shipLines", list);
        JSONObject response = this.remoteRequestMethod(map, paraValue, paraUrl);
        // 如果生成出货单成功，存储出货单编号
        if (response.getBooleanValue("success")) {
            pmInvoiceApplyEntity.setErpshipdocno(response.getString("result"));
            this.updateEntity(pmInvoiceApplyEntity);
        }
        response.put("pmstate", PmSystemConst.BillSendExceptionType.ShipCreate);
        return response;
    }

    /**
     * @Description: 审批出货订单
     * @author houyuhang
     * @date  2023年1月17日
     */
    @Transactional(rollbackFor = Exception.class)
    public JSONObject pmAddErpShipApproval(PmInvoiceApplyEntity pmInvoiceApplyEntity) throws Exception {
        String paraUrl = ParameterCache.getValue("ERPServiceUrl_ShipApprove");
        String paraValue = ParameterCache.getValue("ERPServiceUrl_Token");
        String orgcode = pmInvoiceApplyEntity.getInvoiceorgcode();
        JSONObject map = new JSONObject();
        map.put("docNo", pmInvoiceApplyEntity.getErpshipdocno());
        map.put("status", 2);
        map.put("orgcode", orgcode);
        JSONObject response = this.remoteRequestMethod(map, paraValue, paraUrl);
        response.put("pmstate", PmSystemConst.BillSendExceptionType.ShipApproval);
        return response;
    }
    /**
     * @return
     * @author: houyuhang
     * @date: 2023-01-17
     * @description: 创建应收接口
     * @modify:
     */
    @Transactional(rollbackFor = Exception.class)
    public JSONObject pmAddErpArbill(PmInvoiceApplyEntity pmInvoiceApplyEntity) throws Exception {
        String paraValue = ParameterCache.getValue("ERPServiceUrl_Token");
        String paraUrl = ParameterCache.getValue("ERPServiceUrl_CreateArbill");
        String orgcode = pmInvoiceApplyEntity.getInvoiceorgcode();
        JSONObject map = new JSONObject();
        map.put("system", "pm");
        map.put("ident", pmInvoiceApplyEntity.getTableName()+"_"+pmInvoiceApplyEntity.getId());
        map.put("orgCode", orgcode);
        map.put("docType", "12");
        map.put("cusOrSuppCode", pmInvoiceApplyEntity.getErpcode()); // erp客户编码
        map.put("cusOrSuppSiteCode", pmInvoiceApplyEntity.getErpcode());
        map.put("currency", "C001");
        map.put("sourceType", pmInvoiceApplyEntity.getTableName());
        map.put("sourceDocNo", pmInvoiceApplyEntity.getDocno());
        map.put("invoiceDateGL", pmInvoiceApplyEntity.getInvoicedate());
        map.put("invoiceNum", pmInvoiceApplyEntity.getInvoiceno());
        map.put("invoiceDate", pmInvoiceApplyEntity.getInvoicedate());
        map.put("memo", datacodeCache.getValueDynamic("PmInvoiceType", pmInvoiceApplyEntity.getInvoicetype(), "code", "name")); // 备注
        // 根据销售单编号获取出货单信息
        JSONArray dataArray = this.getShipInfoFromERP(pmInvoiceApplyEntity);
        // 立项明细信息
        ArrayList list = new ArrayList();
        for (int i = 0; i < dataArray.size(); i++) {
            JSONObject dataObject = dataArray.getJSONObject(i);
            JSONObject line = new JSONObject();
            // 出货（退货）立账分期子表ID
            line.put("lineId", dataObject.getLong("termId"));
            // 立账数量
            line.put("amount", dataObject.getBigDecimal("canInvoiceQty"));
            // 含税单价
            line.put("taxPrice", dataObject.getBigDecimal("taxPrice"));
            // 未税单价
            line.put("noTaxPrice", dataObject.getBigDecimal("netPrice"));
            // 税额
            line.put("taxMoney", dataObject.getBigDecimal("taxMoney"));
            // 未税金额
            line.put("noTaxMoney", dataObject.getBigDecimal("netMoney"));
            // 总金额
            line.put("totalMoney", dataObject.getBigDecimal("canInvoiceMoney"));
            // 税组合
            line.put("taxScedule", dataObject.getString("scheduleCode"));
            list.add(line);
        }
        map.put("accrueDetails", list);
        JSONObject response = this.remoteRequestMethod(map, paraValue, paraUrl);
        response.put("pmstate", PmSystemConst.BillSendExceptionType.ArbillCreate);
        return response;
    }
    /**
     * @return
     * @author: houyuhang
     * @date: 2023-01-29
     * @description: 从ERP系统获取出货单信息
     * @modify:
     */
    public JSONArray getShipInfoFromERP(PmInvoiceApplyEntity pmInvoiceApplyEntity) {
        String token = ParameterCache.getValue(PmSystemConst.DataServiceToken);
        String url = ParameterCache.getValue(PmSystemConst.DataServiceUrl);
        JSONObject innerparams = new JSONObject();
        innerparams.put("orgcode", pmInvoiceApplyEntity.getInvoiceorgcode());
        innerparams.put("sodocnos", "'" + pmInvoiceApplyEntity.getErpdocno().replaceAll(",", ",',") + "'");
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("templateid", ParameterCache.getValue("PMQueryERPShip"));
        jsonObject.put("paramsMap", innerparams);
        JSONObject resObject = this.remoteRequestMethod(jsonObject, token, url);
        return resObject.getJSONObject("result").getJSONArray("dataList");
    }
    /**
     * @return
     * @author: houyuhang
     * @date: 2023-02-01
     * @description: 如果生成出货单、应收单失败，将错误信息生成待办发送到开票平台
     * @modify:
     */
    public void startApprovalInvoice(PmInvoiceApplyEntity pmInvoiceApplyEntity, JSONObject exceptionRes) {
        String paraUrl = ParameterCache.getValue("BillServiceUrl_Approval") + "/sync?appkey=" + ParameterCache.getValue("BillDataSysAppKey");
        StringBufferProxy reason = new StringBufferProxy();
        if (PmSystemConst.BillSendExceptionType.ShipCreate.equals(exceptionRes.getString("pmstate"))) {
            reason.appendSingle("工程项目单号：{0}，料号：{1}，生成出货单失败，请手动生成出货单、应收单！", pmInvoiceApplyEntity.getDocno(), pmInvoiceApplyEntity.getProjectcode());
        } else if (PmSystemConst.BillSendExceptionType.ShipApproval.equals(exceptionRes.getString("pmstate"))) {
            reason.appendSingle("工程项目单号：{0}，料号：{1}，出货单号：{2}，出货单审批失败，请手动审批出货单并生成应收单！", pmInvoiceApplyEntity.getDocno(), pmInvoiceApplyEntity.getProjectcode(), pmInvoiceApplyEntity.getErpshipdocno());
        } else if (PmSystemConst.BillSendExceptionType.ArbillCreate.equals(exceptionRes.getString("pmstate"))) {
            reason.appendSingle("工程项目单号：{0}，料号：{1}，出货单号：{2}，生成应收单失败，请手动生成应收单！", pmInvoiceApplyEntity.getDocno(), pmInvoiceApplyEntity.getProjectcode(), pmInvoiceApplyEntity.getErpshipdocno());
        }
        JSONObject map = new JSONObject();
        map.put("operatedate", DateUtil.now());
        map.put("sourceapp", "PM");
        map.put("sourcedocno", pmInvoiceApplyEntity.getDocno()); // 工程项目单号
        map.put("reason", reason.toString()); // 报错原因
        map.put("operatorcode", this.getUsercodeForBillSystem(pmInvoiceApplyEntity)); // 发票系统处理人员工号
        JSONObject response = this.remoteRequestMethod(map, paraUrl);
    }

    /**
     * @return
     * @author: houyuhang
     * @date: 2023-02-02
     * @description: 根据开票的组织确定发票系统的处理人员
     * @modify:
     */
    public String getUsercodeForBillSystem(PmInvoiceApplyEntity pmInvoiceApplyEntity) {
        String orgcode = pmInvoiceApplyEntity.getInvoiceorgcode();
        List<Map<String, Object>> billList = datacodeCache.getCodeListMap("BillSystemUsercode", "", "sortcode");
        if (CollectionUtil.isEmpty(billList)) {
            return "";
        }
        // 科远单据并在鼎信电力工程下
        for (Map<String, Object> billMap : billList) {
            if (orgcode.contains(ConvertUtil.convertToString(billMap.get("code")))) {
                return ConvertUtil.convertToString(billMap.get("name"));
            }
        }
        return ConvertUtil.convertToString(billList.get(0).get("name"));
    }
}
